package com.dingreading.cloud.web.controller;

import com.alibaba.fastjson.JSONObject;
import com.dingreading.cloud.common.base.R;
import com.dingreading.cloud.common.util.DateUtil;
import com.dingreading.cloud.common.util.DescribeException;
import com.dingreading.cloud.common.util.HttpUtils;
import com.dingreading.cloud.common.util.wechat.AuthToken;
import com.dingreading.cloud.common.util.wechat.WxPayBusiness;
import com.dingreading.cloud.web.entity.WxAcecGzhUser;
import com.dingreading.cloud.web.service.WxAcecGzhUserService;
import com.dingreading.cloud.web.util.redis.RedisService;
import com.dingreading.cloud.web.util.wxgzh.GzhUrlUtils;
import com.dingreading.cloud.web.util.wxgzh.TextMessage;
import com.dingreading.cloud.web.util.wxgzh.WxMessageType;
import com.dingreading.cloud.web.util.wxgzh.WxMessageUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.*;

@RefreshScope
@RestController
@RequestMapping("/front/wechat")
@Api(tags = "ACEC微信开发管理")
public class AcecGzhController {

    @Value("${wx.nj.appId}")
    private String appId;
    @Value("${wx.nj.appSecret}")
    private String appSecret;

    @Resource
    WxAcecGzhUserService wxAcecGzhUserService;
    @Autowired
    private RedisService redisService;

    public static final String ACEC_ACCESS_TOKEN = "acec_access_token";

    private static final String TICKET_URL = "https://www.njacec.cn";

    /**
     * 接受微信发送的消息
     *
     * @param request 公参
     * @return 返回结果
     */
    @ApiOperation(value = "微信推送事件-验证（ACEC聚心众合）")
    @GetMapping(value = "/checkToken")
    public String checkTokenGet(
            HttpServletRequest request,
            HttpServletResponse response
    ) {
        try {
//            System.out.println("微信推送事件");
            String signature = request.getParameter("signature");
            String timestamp = request.getParameter("timestamp");
            String nonce = request.getParameter("nonce");
            String echoStr = request.getParameter("echostr");
            boolean checkSignature = checkSignature(signature, timestamp, nonce, "zxjhzxjhzxjh");
            if (checkSignature) {
                return echoStr;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "";
    }

    @ApiOperation(value = "微信推送事件-接收消息（ACEC聚心众合）")
    @PostMapping(value = "/checkToken")
    public void checkTokenPost(
            HttpServletRequest request,
            HttpServletResponse response
    ) {
        try {
//            System.out.println("微信接收事件");
            request.setCharacterEncoding("UTF-8");
            response.setCharacterEncoding("UTF-8");

            Map<String, String> requestMap = WxMessageUtil.parseXml(request);
            System.out.println("解析====>" + requestMap.toString());

            String messageType = requestMap.get("MsgType");
            String eventType = requestMap.get("Event");
            // 发送方帐号（open_id）
            String openid = requestMap.get("FromUserName");
            // 公众帐号
            String toUserName = requestMap.get("ToUserName");
            // 消息类型
            String msgType = requestMap.get("MsgType");
            // 事件KEY值
            String eventKey = requestMap.get("EventKey");

            if (messageType.equals(WxMessageType.EVENT.getCode())) {
                //判断消息类型是否是事件消息类型
//                System.out.println("公众号====>事件消息");
//                System.out.println("openid:" + openid);
//                System.out.println("Event:" + eventType);
                if (eventType.equals(WxMessageType.SUBSCRIBE.getCode())) {
//                    System.out.println("公众号====>新用户关注");
                    // 获取公众号的场景值
                    String scene = getScene(eventKey);
                    // 保存微信公众号的用户信息
                    saveAcecGzhUser(openid, scene);
                    // 关注回复文字
                    subscribeSendTextMsg(response, toUserName, openid, scene);
                } else if (eventType.equals(WxMessageType.UNSUBSCRIBE.getCode())) {
//                    System.out.println("公众号====>用户取消关注");
                    // 更新取关时间
                    wxAcecGzhUserService.updateUnsubscribeTime(openid);
                } else if (eventType.equals(WxMessageType.SCAN.getCode())) {
//                    System.out.println("公众号====>已关注时扫码公众号二维码");
                    // 关注后扫公众号二维码回复文字
//                    subscribeSendTextMsg(response, toUserName, openid, eventKey);
                    // 获取公众号的场景值
                    String scene = getScene(eventKey);
                    // 更新用户的来源
                    if (StringUtils.isNotBlank(scene) && !scene.equals("0"))
                        updateAcecGzhUser(openid, scene);
                } else {
//                    System.out.println("微信类型===>" + messageType);
//                    System.out.println("公众号===>其他");
                }
            } else if (messageType.equals(WxMessageType.TEXT.getCode())) {
                // 响应消息
//                System.out.println("用户输入文本信息");
                String content = requestMap.get("Content");
                // 回复文本消息
                returnMsg(response, content, toUserName, openid, msgType);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @ApiOperation(value = "ACEC微信公众号获取openid")
    @PostMapping(value = "/getAcecOpenId", produces = "application/json; charset=UTF-8")
    public R<Object> getAcecOpenId(
            @RequestParam(value = "code") @ApiParam(value = "微信授权码") String code
    ) throws Exception {

        AuthToken authToken = WxPayBusiness.Init().getAccessToken(code, appId, appSecret);
        System.out.println("authToken = " + JSONObject.toJSONString(authToken));
        if (authToken != null)
            return R.ok(authToken.getOpenid());
        return R.fail("获取失败");
    }

    @ApiOperation(value = "ACEC微信公众号生成带参数二维码")
    @GetMapping(value = "/createQrCode", produces = "application/json; charset=UTF-8")
    public R<Object> createQrCode(
            @RequestParam(value = "from") @ApiParam(value = "来源参数") Integer from
    ) throws Exception {


        String accessToken = getAcecAccessToken();
        if (StringUtils.isBlank(accessToken))
            return R.fail("微信令牌accessToken获取失败");

        String r = GzhUrlUtils.createForeverTicket(accessToken, from);
        JSONObject jsonObject = new JSONObject();
        if (StringUtils.isNotBlank(r)) {
            jsonObject = JSONObject.parseObject(r);
            String ticket = jsonObject.getString("ticket");
            if (StringUtils.isNotBlank(ticket)) {
                return R.ok("https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket=" + ticket);
            }
        }

        return R.fail("创建二维码失败");
    }

    @ApiOperation(value = "ACEC微信公众号生成带参数二维码并展示")
    @GetMapping(value = "/showQrCode", produces = "application/json; charset=UTF-8")
    public void showQrCode(
            HttpServletRequest request,
            HttpServletResponse response,
            @RequestParam(value = "from") @ApiParam(value = "来源参数") Integer from
    ) throws Exception {
        String imageUrl = "";
        String accessToken = getAcecAccessToken();
        if (StringUtils.isBlank(accessToken)) {
            throw new DescribeException("微信令牌accessToken获取失败");
        }

        String r = GzhUrlUtils.createForeverTicket(accessToken, from);
        JSONObject jsonObject = new JSONObject();
        if (StringUtils.isNotBlank(r)) {
            jsonObject = JSONObject.parseObject(r);
            String ticket = jsonObject.getString("ticket");
            if (StringUtils.isNotBlank(ticket)) {
                imageUrl = "https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket=" + ticket;
            }
        }

        // 设置响应内容类型
        response.setContentType("text/html;charset=UTF-8");
        // 输出HTML页面
        PrintWriter out = response.getWriter();
        out.println("<!DOCTYPE html>");
        out.println("<html>");
        out.println("<head>");
        out.println("<title>显示公众号二维码</title>");
        out.println("</head>");
        out.println("<body>");
        out.println("<h1>渠道：" + from + "</h1>");
        out.println("<img src='" + imageUrl + "' alt='二维码' />");
        out.println("</body>");
        out.println("</html>");
    }

    /**
     * 设置抖音相关调用
     */
//    private void setDouYin(String openid, String applyName, String uid) {
//        String userUid = "";
//        if (StringUtils.isNotBlank(applyName)) {
//            if (applyName.equals("douyin")) {
//                if (StringUtils.isBlank(uid))
//                    System.out.println("关注公众号后，获取场景uid失败");
//                DyClickId dyClickId = dyClickIdService.getByUid(uid);
//                if (dyClickId == null || StringUtils.isBlank(dyClickId.getUserUid()))
//                    System.out.println("关注公众号后，获取抖音用户信息失败");
//                userUid = dyClickId.getUserUid();
//                long l = dyClickIdService.updateOpenid(uid, openid);
//                if (l <= 0) System.out.println("关注公众号后，抖音用户绑定openid失败");
//            }
//        }
//
//        // 添加访问记录
//        ApplyBrowseLog log = new ApplyBrowseLog();
//        log.setApplyName(applyName);
//        log.setPageName("关注ACEC公众号");
//        log.setUserUid(userUid);
//        log.setAddTime(DateUtil.getNowDatetime());
//        browseLogService.saveOrUpdate(log);
//
//        /// 抖音api回调-有效获客
//        if (applyName.equals("douyin") && StringUtils.isNotBlank(userUid))
//            apiReturn("customer_effective", userUid);
//    }

    /**
     * 验证微信签名
     */
    public boolean checkSignature(String signature, String timestamp, String nonce, String token) {
        if (StringUtils.isBlank(signature) || StringUtils.isBlank(timestamp) || StringUtils.isBlank(nonce) || StringUtils.isBlank(token))
            return false;
        // 1.将token、timestamp、nonce三个参数进行字典序排序
        String[] arr = new String[]{token, timestamp, nonce};
        Arrays.sort(arr);
        if (null == arr || arr.length == 0) {
            return false;
        }
        // 2. 将三个参数字符串拼接成一个字符串进行sha1加密
        StringBuilder content = new StringBuilder();
        for (int i = 0; i < arr.length; i++) {
            content.append(arr[i]);
        }
        MessageDigest md = null;
        String tmpStr = null;
        try {
            md = MessageDigest.getInstance("SHA-1");
            // 将三个参数字符串拼接成一个字符串进行sha1加密
            byte[] digest = md.digest(content.toString().getBytes());
            tmpStr = byteToStr(digest);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        content = null;
        // 3.将sha1加密后的字符串可与signature对比，标识该请求来源于微信
        return tmpStr != null && tmpStr.equals(signature.toUpperCase());
    }

    private static String byteToStr(byte[] byteArray) {
        StringBuilder strDigest = new StringBuilder();
        for (int i = 0; i < byteArray.length; i++) {
            strDigest.append(byteToHexStr(byteArray[i]));
        }
        return strDigest.toString();
    }

    private static String byteToHexStr(byte mByte) {
        char[] Digit = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A',
                'B', 'C', 'D', 'E', 'F'};
        char[] tempArr = new char[2];
        tempArr[0] = Digit[(mByte >>> 4) & 0X0F];
        tempArr[1] = Digit[mByte & 0X0F];
        String s = new String(tempArr);
        return s;
    }

    /**
     * 关注公众号时回复文本
     */
    private void subscribeSendTextMsg(HttpServletResponse response, String toUserName, String openid, String scene) throws Exception {
        PrintWriter out = response.getWriter();
        TextMessage textMessage = new TextMessage();
        textMessage.setFromUserName(toUserName);
        textMessage.setToUserName(openid);
        textMessage.setMsgType("text");
        textMessage.setCreateTime(System.currentTimeMillis());
        textMessage.setContent("感谢您关注（南京）教育品牌展览会官方微信，您可以点击下方菜单栏了解大会介绍、参会指南、个人中心等相关信息。\n\n" +
                "自2017年至今，（南京）教育品牌展览会已成功举办五届，以务实中国教育者需求为核心，甄选国内外优质教育产品，打造教育者的“双11”，为教育品牌实现由内到外的升级优化提供一站式解决方案。\n\n" +
                "展览时间：2025.05.07-05.09\n" +
                "展览地址：南京国际展览中心龙蟠路88号\n" +
                "领票/验票/购票 请点击：" + TICKET_URL);
        String message = WxMessageUtil.textMessageToXml(textMessage);
        out.println(message);
        // 关闭流
        out.close();
    }

    /**
     * 保存微信公众号的用户信息
     */
    private void saveAcecGzhUser(String openid, String source) throws Exception {
        String accessToken = getAcecAccessToken();
        if (StringUtils.isBlank(accessToken))
            throw new DescribeException("微信令牌accessToken获取失败");

        JSONObject userInfo = GzhUrlUtils.getUserInfo(openid, accessToken);
        WxAcecGzhUser user = null;
        if (Objects.nonNull(userInfo)) {
            openid = userInfo.getString("openid");
            if (StringUtils.isNotBlank(openid)) {
                String nowTime = DateUtil.getNowDatetimeStr();
                Integer subscribe_time = userInfo.getInteger("subscribe_time");
                if (null != subscribe_time && subscribe_time > 0) {
                    // 时间戳1382694957
                    nowTime = DateUtil.getDefaultTimeStr(new Date(subscribe_time * 1000L));
                }

                List<WxAcecGzhUser> userList = wxAcecGzhUserService.getByOpenid(openid);
                if (CollectionUtils.isEmpty(userList)) {
                    //新增
                    user = new WxAcecGzhUser();
                    user.setUnionid(userInfo.getString("unionid"));
                    user.setOpenid(userInfo.getString("openid"));
                    user.setOriginSubscribeScene(userInfo.getString("subscribe_scene"));
                    user.setOriginSubscribeTime(nowTime);
                    user.setAddTime(nowTime);
                    if (StringUtils.isNotBlank(source)) {
                        user.setOriginSource(source);
                        user.setSource(source);
                    } else {
                        user.setOriginSource("0");
                        user.setSource("0");
                    }
                } else {
                    user = userList.get(0);
                    if (StringUtils.isNotBlank(source) && !source.equals("0")) {
                        user.setSource(source);
                    }
                }
                user.setSex(userInfo.getInteger("sex"));
                user.setLanguage(userInfo.getString("language"));
                user.setGroupid(userInfo.getInteger("groupid"));
                user.setTagidList(userInfo.getString("tagid_list"));
                user.setQrScene(userInfo.getInteger("qr_scene"));
                user.setQrSceneStr(userInfo.getString("qr_scene_str"));
                user.setSubscribe(userInfo.getInteger("subscribe"));
                user.setSubscribeScene(userInfo.getString("subscribe_scene"));
                user.setRemark(userInfo.getString("remark"));
                user.setSubscribeTime(nowTime);
                user.setEditTime(nowTime);
                wxAcecGzhUserService.saveOrUpdate(user);
            }
        }
    }

    /**
     * 保存微信公众号的用户信息
     */
    private void updateAcecGzhUser(String openid, String source) throws Exception {
        wxAcecGzhUserService.updateSource(openid, source);
    }

    /**
     * 抖音落地页「API回传」
     */
    private void apiReturn(String eventType, String clickid) {
        String apiUrl = "https://analytics.oceanengine.com/api/v2/conversion";
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("event_type", eventType);
        JSONObject callbackObj = new JSONObject();
        callbackObj.put("callback", clickid);
        JSONObject adObj = new JSONObject();
        adObj.put("ad", callbackObj);
        jsonObject.put("context", adObj);
        jsonObject.put("timestamp", System.currentTimeMillis());
        String str = jsonObject.toJSONString();
        String result = HttpUtils.post(apiUrl, str);

        System.out.println("抖音 " + eventType + "回调=" + result);
    }

    /**
     * 获取微信accessToken令牌
     */
    private String getAcecAccessToken() {
        String accessToken = (String) redisService.get(ACEC_ACCESS_TOKEN);
        if (StringUtils.isBlank(accessToken)) {
            accessToken = WxPayBusiness.Init().getAccessToken(appId, appSecret);
            if (StringUtils.isNotBlank(accessToken)) {
                redisService.set(ACEC_ACCESS_TOKEN, accessToken, 7200);
            } else {
                accessToken = "";
            }
        }
        return accessToken;
    }

    /**
     * 获取公众号二维码参数
     */
    private String getScene(String eventKey) {
        String scene = "0";
        String uid = "";
        if (StringUtils.isNotBlank(eventKey) && eventKey.contains("qrscene_")) {
            // 首次关注时获取方式
            String qrscene = StringUtils.substringAfterLast(eventKey, "qrscene_");
            if (StringUtils.isNotBlank(qrscene)) {
                if (qrscene.contains("&")) {
                    String[] split = qrscene.split("&");
                    if (split.length == 2) {
                        scene = split[0];
                        uid = split[1];
                    }
                } else {
                    scene = qrscene;
                }
            }
        } else {
            // 再次扫码时获取方式
            scene = eventKey;
        }
        return scene;
    }

    /**
     * 回复文本消息
     */
    private void returnMsg(
            HttpServletResponse response, String content, String toUserName, String openid, String msgType
    ) throws Exception {
        if (StringUtils.isNotBlank(content)) {
            if (content.contains("票")) {
                PrintWriter out = response.getWriter();
                TextMessage textMessage = new TextMessage();
                textMessage.setFromUserName(toUserName);
                textMessage.setToUserName(openid);
                textMessage.setMsgType(msgType);
                textMessage.setCreateTime(System.currentTimeMillis());
                textMessage.setContent("领票/验票/购票 请点击：" + TICKET_URL);
                String message = WxMessageUtil.textMessageToXml(textMessage);
                out.println(message);
                // 关闭流
                out.close();
            }
        }
    }
}
